﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using blackhouse.BlackApart.Business.Reservations;

namespace blackhouse.BlackApart.Business.ApartmentServices {
    public abstract class ReservationAdditionalService {

        #region Fields

        protected IWebReservation reservation;
        protected List<ReservationAdditionalServiceUnit> lines;
        private string clientReview;
        private bool tryGetClientReview;

        #endregion

        #region Properties

        public IAdditionalService Service { get; private set; }

        public double Price {
            get {
                if (this.Lines.Count > 0)
                    return this.Lines.Sum(u => u.UnitPrice * u.Quantity);
                else
                    return 0;
            }
        }

        protected List<ReservationAdditionalServiceUnit> Lines {
            get {
                if (this.lines == null) {
                    this.lines = this.GetOrderLines();
                    if (this.lines != null)
                        this.tryGetClientReview = true;
                    else
                        this.lines = new List<ReservationAdditionalServiceUnit>();
                }
                return this.lines;
            }
        }

        public int ForApartment {
            get { // usługa składa się z wielu linii ale wszystkie są przypisane do tego samego apartamentu
                if (this.Lines.Count > 0)
                    return this.Lines.First().ApartmentId;
                else
                    return 0;
            }
        }

        public int Quantity {
            get {
                if (this.Lines.Count > 0)
                    return this.Lines.Sum(u => u.Quantity);
                else
                    return 0;
            }
        }

        public string ClientReview {
            get {
                if (string.IsNullOrEmpty(this.clientReview) && this.Lines != null) {
                    if (this.tryGetClientReview && !string.IsNullOrEmpty(this.Service.ReviewTitle)) { // wszystko wskazuje na to, że mogą istnieć uwagi klienta, które trzeba pobrać
                        this.clientReview = this.GetClientReview();
                        this.tryGetClientReview = false;
                    }
                }
                return this.clientReview;
            }
            set {
                this.clientReview = value;
            }
        }

        #endregion

        #region Constructors

        public ReservationAdditionalService(IWebReservation reservation, IAdditionalService service) {
            this.reservation = reservation;
            this.Service = service;
        }

        #endregion

        #region Methods

        protected abstract void SaveOrder();
        protected abstract List<ReservationAdditionalServiceUnit> GetOrderLines();
        protected abstract string GetClientReview();

        public void Save() {
            if (this.Lines.Count > 0)
                this.SaveOrder();
        }

        public void BookService() {
            this.BookService(DateTime.MinValue);
        }

        public void BookService(DateTime forDay) {
            this.BookService(forDay, 0);
        }

        public void BookService(DateTime forDay, int count) {

            // Sprawdzenie paramentrów
            if (forDay != DateTime.MinValue && (this.Service.ServiceFor & ServiceFor.Day) != ServiceFor.Day)
                throw new InvalidOperationException("Nie można zamówić " + this.Service.ServiceName + " na dzień, ponieważ usługa nie obsługuje takiego wariantu");

            if (count != 0 && (this.Service.ServiceFor & ServiceFor.Quantity) != ServiceFor.Quantity)
                throw new InvalidOperationException("Nie można zamówić " + this.Service.ServiceName + " na ilość, ponieważ usługa nie obsługuje takiego wariantu");

            int apartmentId = 0;
            if ((this.Service.ServiceFor & ServiceFor.Room) == ServiceFor.Room) {
                if (this.reservation.ApartmentReservation.Length != 1)
                    throw new InvalidOperationException("Nie można zamówić " + this.Service.ServiceName + " do pokoju, ponieważ liczba zamówionych pokoi jest większa niż jeden, co nie jest obsługiwane przez www.");
                apartmentId = this.reservation.ApartmentReservation.First().ApartmentId;
            }

            this.AddServiceForDay(forDay, count, apartmentId);
        }

        protected int AddServiceForDay(DateTime day, int quantity, int apartmentId) {
            int pQ = 0;

            ReservationAdditionalServiceUnit u = new ReservationAdditionalServiceUnit();
            u.Date = day.Date;
            u.Quantity = quantity;
            //u.UnitPrice = unitPrice;
            u.ApartmentId = apartmentId;
            //u.Price = unitPrice * quantity;
            //u.ServiceForSignature = (int)serviceFor;
            int idx = this.Lines.IndexOf(u);
            if (idx >= 0) {
                pQ = this.Lines[idx].Quantity;
                this.Lines.RemoveAt(idx);
            }
            this.Lines.Add(u);
            return pQ;
        }

        public int GetQuantityPerDay(int apartmentId) {
            var alq = this.Lines.Where(rasu => rasu.ApartmentId == apartmentId);
            switch (this.Service.ServiceFor) {
                case ServiceFor.None:
                case ServiceFor.Day:
                    return this.Lines.Any() ? 1 : 0;
                case ServiceFor.Room:
                case ServiceFor.RoomForDay:
                    return alq.Any() ? 1 : 0;
                case ServiceFor.Quantity:
                    return this.Lines.Sum(rasu => rasu.Quantity);
                case ServiceFor.QuantityForDay:
                    return Convert.ToInt32(alq.Average(rasu => rasu.Quantity));
                case ServiceFor.All:
                    return alq.Sum(rasu => rasu.Quantity);
                default:
                    return 0;
            }
        }

        #endregion

    }
}
